#include <iostream>
#include <string>
#include <cstdio>
#include <cstdbool>
#include <pthread.h>
#include <unistd.h>

// 了解关于条件变量的接口,理解什么是线程同步

typedef void(*func_t)(std::string &name,pthread_mutex_t *pmutex,pthread_cond_t *pcond);

const int THREAD_NUM=4;

// 全局条件变量
//pthread_cond_t cond=PTHREAD_COND_INITIALIZER;

volatile bool flag=true;

class ThreadData
{
public:
    std::string _name;
    func_t _func;
    pthread_mutex_t *_pmutex;
    pthread_cond_t *_pcond;
public:
    ThreadData(std::string &name,func_t func,pthread_mutex_t *pmutex,pthread_cond_t *pcond)
        :_name(name),_func(func),_pmutex(pmutex),_pcond(pcond)
    {}
};

void func1(std::string &name,pthread_mutex_t *pmutex,pthread_cond_t *pcond)
{
    while(flag)
    {
        // int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
        pthread_mutex_lock(pmutex);

        // 进行等待
        pthread_cond_wait(pcond,pmutex);
        std::cout<<name<<std::endl;

        pthread_mutex_unlock(pmutex);
        //sleep(1);
    }
}

void func2(std::string &name,pthread_mutex_t *pmutex,pthread_cond_t *pcond)
{
    while(flag)
    {
        pthread_mutex_lock(pmutex);
        pthread_cond_wait(pcond,pmutex);
        std::cout<<name<<std::endl;
        pthread_mutex_unlock(pmutex);
        //sleep(1);
    }
}

void func3(std::string &name,pthread_mutex_t *pmutex,pthread_cond_t *pcond)
{
    while(flag)
    {
        pthread_mutex_lock(pmutex);
        pthread_cond_wait(pcond,pmutex);
        std::cout<<name<<std::endl;
        pthread_mutex_unlock(pmutex);
        //sleep(1);
    }
}

void func4(std::string &name,pthread_mutex_t *pmutex,pthread_cond_t *pcond)
{
    while(flag)
    {
        pthread_mutex_lock(pmutex);
        pthread_cond_wait(pcond,pmutex);
        std::cout<<name<<std::endl;
        pthread_mutex_unlock(pmutex);
        //sleep(1);
    }
}

void* Entry(void* args)
{
    ThreadData *ptd=static_cast<ThreadData*>(args);

    ptd->_func(ptd->_name,ptd->_pmutex,ptd->_pcond);

    delete ptd;

    return nullptr;
}

int main(/*int argc,char** argv,char* env*/)
{
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex,nullptr);

    // 定义局部条件变量
    // int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
    pthread_cond_t cond;
    pthread_cond_init(&cond,nullptr);

    pthread_t tids[THREAD_NUM];

    func_t funcs[THREAD_NUM]={func1,func2,func3,func4};

    // 创建线程
    for(int i=0;i<THREAD_NUM;i++)
    {
        std::string name(std::string("Thread ")+std::to_string(i+1));

        ThreadData *ptd=new ThreadData(name,funcs[i],&mutex,&cond);

        pthread_create(tids+i,nullptr,Entry,(void*)ptd);
    }

    sleep(6);

    for(int i=0;i<9;i++)
    {
        std::cout << "resume thread run code ...." <<9-i<< std::endl;

        // int pthread_cond_broadcast(pthread_cond_t *cond);
        //pthread_cond_broadcast(&cond);

        // 唤醒一个线程
        //  int pthread_cond_signal(pthread_cond_t *cond);
        pthread_cond_signal(&cond);

        sleep(1);
    }

    flag=false;

    pthread_cond_broadcast(&cond);

    // 线程等待
    for(int i=0;i<THREAD_NUM;i++)
    {
        pthread_join(tids[i],nullptr);
        std::cout<<"Thread: "<<tids[i]<<" quit "<<std::endl;
    }

    // int pthread_cond_destroy(pthread_cond_t *cond);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    return 0;
}


// // 了解关于锁的接口,用来解决访问临界资源的问题
// const int THREAD_NUM=3;

// int tickets=10000;
// // 定义全局锁
// //pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

// struct ThreadData
// {
//     std::string _name_;
//     pthread_mutex_t *_pmutex_;

//     ThreadData(const std::string &name,pthread_mutex_t *pmutex):_name_(name),_pmutex_(pmutex)
//     {}
// };

// void *GetTicket(void *args)
// {
//     ThreadData *ptd=(ThreadData*)args;

//     while(true) // 了解什么是临界区与临界资源
//     {   
//         // 在临界区之间进行加锁与解锁
//         // 加锁: int pthread_mutex_lock(pthread_mutex_t *mutex);
//         pthread_mutex_lock(ptd->_pmutex_);
//         if(tickets>0) 
//         {
//             usleep(2000); // 某线程进来之后,还没有开始减减,就被切换了 
//             tickets--; // 1,将数据从内存加载到寄存器 2,CPU在寄存器中对数据减减 3,将处理完的数据写回内存(正好被切换了)

//             // 线程抢到票之后,还剩下多少票
//             printf("%s : tickets : %d\n",ptd->_name_.c_str(),tickets);

//             // 解锁: int pthread_mutex_unlock(pthread_mutex_t *mutex);
//             pthread_mutex_unlock(ptd->_pmutex_);
//         }
//         else
//         { 
//             // 解锁: int pthread_mutex_unlock(pthread_mutex_t *mutex);
//             pthread_mutex_unlock(ptd->_pmutex_);
//             break;
//         }

//         usleep(2000);
//     }

//     delete ptd;

//     return nullptr;
// }

// int main()
// {
//     // 定义局部锁
//     pthread_mutex_t mutex;
//     // 初始化: int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
//     pthread_mutex_init(&mutex,nullptr); 

//     pthread_t tids[THREAD_NUM];

//     // 创建线程
//     for(int i=0;i<THREAD_NUM;i++)
//     {
//         std::string name="Thread ";
//         name+=std::to_string(i+1);
//         ThreadData *ptd=new ThreadData(name,&mutex);

//         pthread_create(tids+i,nullptr,GetTicket,(void*)ptd);
//     }

//     // 线程等待
//     for(int i=0;i<THREAD_NUM;i++)
//     {
//         pthread_join(tids[i],nullptr);
//     }

//     std::cout<<"join success"<<std::endl;

//     // 销毁: int pthread_mutex_destroy(pthread_mutex_t *mutex);
//     pthread_mutex_destroy(&mutex);

//     while(true)
//     {}

//     return 0;
// }